#include "MJPEGServer.hpp"
#include <boost/intrusive/detail/iterator.hpp>
#include <crow.h>
#include <crow/app.h>
#include <opencv2/core/hal/interface.h>
#include <opencv2/dnn/dnn.hpp>
#include <opencv2/imgcodecs.hpp>
#include <vector>

Encoder::Encoder(const std::string &port)
    : BaseEncoder(""), ServerPort(std::stoi(port)) {
  CROW_WEBSOCKET_ROUTE(app, "/preview/JPG")
      .onopen([this](crow::websocket::connection &conn) {
        connList.push_back(&conn);
      })
      .onclose(
          [this](crow::websocket::connection &conn, const std::string &reason) {
            auto delconn = std::find(connList.begin(), connList.end(), &conn);
            connList.erase(delconn);
          });
  workThread = std::thread(
      [this]() { app.bindaddr("0.0.0.0").port(3602).multithreaded().run(); });
}

Encoder::~Encoder() {
  if (workThread.joinable()) {
    app.stop();
    workThread.join();
  }
}

const static std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};

void Encoder::StartStream(int width, int height, const ImageType &type) {
  imgWidth = width;
  imgHeight = height;
  imgType = type;
  switch (imgType) {
  case ImageType::GREY:
    imageSize = width * height;
    image = cv::Mat(imgHeight, imgWidth, CV_8UC1);
    break;
  case ImageType::RGB8:
    imageSize = width * height * 3;
    image = cv::Mat(imgHeight, imgWidth, CV_8UC3);
    break;
  }
  RunStatus = true;
}

void Encoder::InputImage(const unsigned char *img) {
  memcpy(image.data, img, imageSize);
  std::vector<uchar> buff_bgr;
  cv::imencode(".jpg", image, buff_bgr, params);
  for (auto i : connList)
    i->send_binary(std::string(buff_bgr.begin(), buff_bgr.end()));
}

void Encoder::EndStream() { RunStatus = false; }

bool Encoder::GetStatus() { return RunStatus; };
